﻿Imports TutorialControles

Public Class FrmVariosControlesEjemplo
    Dim modoContacto As Modo = Modo.Nuevo

#Region "Código de prueba"
    Private Sub FrmVariosControlesEjemplo_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        InicializarCategorias()
    End Sub

    Private Sub InicializarCategorias()
        Dim categoriaTreeNode As TreeNode
        Dim categoria As Categoria
        categoriaTreeNode = AddNewCategoria("Amigos")
        categoria = CType(categoriaTreeNode.Tag, Categoria)
        AddNewContactoToCategoria(categoria, "Terzoni", "Marcos", "marcos@gmail.com", New Date(1986, 6, 26), Sexo.Masculino)
        AddNewContactoToCategoria(categoria, "Beccarías", "Ezequiel", "becca@gmail.com", New Date(1980, 5, 10), Sexo.Masculino)
        AddNewContactoToCategoria(categoria, "Verino", "Norberto", "junior@gmail.com", New Date(1990, 4, 15), Sexo.Masculino)
        categoriaTreeNode = AddNewCategoria("Trabajo")
        categoria = CType(categoriaTreeNode.Tag, Categoria)
        AddNewContactoToCategoria(categoria, "NN", "NN", "NN@gmail.com", New Date(1980, 1, 1), Sexo.SinEspecificar)
        categoriaTreeNode = AddNewCategoria("Universidad")
        categoriaTreeNode = AddNewCategoria("Familia")
        categoria = CType(categoriaTreeNode.Tag, Categoria)
        AddNewContactoToCategoria(categoria, "Caballero", "Sofía", "marcos@gmail.com", New Date(1981, 6, 26), Sexo.Femenino)
        AddNewContactoToCategoria(categoria, "Caballero", "Alfonsina", "marcos@gmail.com", New Date(1982, 6, 26), Sexo.Femenino)
        AddNewContactoToCategoria(categoria, "Caballero", "Ana", "marcos@gmail.com", New Date(1983, 6, 26), Sexo.Femenino)
    End Sub
#End Region

    Private Sub AddContactoToCategoria(ByVal categoria As Categoria, ByVal contacto As Contacto)
        categoria.AddNewContacto(contacto)
        Dim indexImage As Integer = -1
        If contacto.Sexo = Sexo.Masculino Then
            indexImage = 2
        ElseIf contacto.Sexo = Sexo.Femenino Then
            indexImage = 1
        Else
            indexImage = -1
        End If
        Dim categoriaTreeNode As TreeNode = getTreeNodeOfCategoria(categoria)
        Dim contactoTreeNode As New TreeNode(contacto.Nombre & " " & contacto.Apellido, indexImage, indexImage)
        contactoTreeNode.Tag = contacto
        categoriaTreeNode.Nodes.Add(contactoTreeNode)
    End Sub

    Private Function getTreeNodeOfCategoria(ByVal categoria As Categoria) As TreeNode
        For Each nodo As TreeNode In tvContactos.Nodes
            If nodo.Tag Is categoria Then
                Return nodo
            End If
        Next
        Return Nothing
    End Function

    Private Function getTreeNodeOfContacto(ByVal contacto As Contacto) As TreeNode
        For Each nodoPadre As TreeNode In tvContactos.Nodes
            For Each nodoHijo As TreeNode In nodoPadre.Nodes
                If nodoHijo.Tag Is contacto Then
                    Return nodoHijo
                End If
            Next
        Next
        Return Nothing
    End Function

    Private Sub AddNewContactoToCategoria(ByVal categoria As Categoria, ByVal apellido As String, ByVal nombre As String, ByVal email As String, ByVal fechaNacimiento As Date, ByVal sexo As Sexo)
        Dim contacto As New Contacto() With {.Apellido = apellido, .Nombre = nombre, .Email = email, .FechaNacimiento = fechaNacimiento, .Sexo = sexo}
        AddContactoToCategoria(categoria, contacto)
    End Sub

    Private Sub btnAgregarCategoria_Click(sender As System.Object, e As System.EventArgs) Handles btnAgregarCategoria.Click
        AddNewCategoria(InputBox("Ingrese el nombre de la nueva categoría", "Nueva categoría"))
    End Sub

    Private Function AddNewCategoria(ByVal nombre As String) As TreeNode
        Dim nuevaCategoria As New Categoria()
        nuevaCategoria.Nombre = nombre
        Dim nodoCategoria As New TreeNode(nuevaCategoria.Nombre, 0, 0)
        nodoCategoria.Tag = nuevaCategoria
        tvContactos.Nodes.Add(nodoCategoria)
        cbCategoria.Items.Add(nuevaCategoria)
        Return nodoCategoria
    End Function

    Private Sub btnEliminarCategoria_Click(sender As System.Object, e As System.EventArgs) Handles btnEliminarCategoria.Click
        Dim nodoSeleccionado As TreeNode
        nodoSeleccionado = tvContactos.SelectedNode
        If nodoSeleccionado Is Nothing Then
            Return
        End If
        If TypeOf nodoSeleccionado.Tag Is Categoria Then
            tvContactos.Nodes.Remove(nodoSeleccionado)
            cbCategoria.Items.Remove(nodoSeleccionado.Tag) 'Borro la categoría del comboBox
            tvContactos.SelectedNode = Nothing
            ResetearCamposPanelContacto()
        Else
            MessageBox.Show("Desde aquí sólo puede eliminar la categoría")
        End If
    End Sub

    Private Sub btnNuevoContacto_Click(sender As System.Object, e As System.EventArgs) Handles btnNuevoContacto.Click
        modoContacto = Modo.Nuevo
        Dim categoriaSeleccionada = getCategoriaSeleccionada()
        ResetearCamposPanelContacto()
        If Not categoriaSeleccionada Is Nothing Then
            cbCategoria.SelectedItem = categoriaSeleccionada
        End If
    End Sub

    Private Function getCategoriaSeleccionada() As Categoria
        Dim nodoSeleccionado As TreeNode = tvContactos.SelectedNode
        Dim categoriaSeleccionada As Categoria = Nothing
        If Not nodoSeleccionado Is Nothing Then
            If TypeOf nodoSeleccionado.Tag Is Categoria Then
                categoriaSeleccionada = CType(nodoSeleccionado.Tag, Categoria)
            End If
        End If
        Return categoriaSeleccionada
    End Function

    Private Function getContactoSeleccionado() As Contacto
        Dim nodoSeleccionado As TreeNode = tvContactos.SelectedNode
        Dim contactoSeleccionado As Contacto = Nothing
        If Not nodoSeleccionado Is Nothing Then
            If TypeOf nodoSeleccionado.Tag Is Contacto Then
                contactoSeleccionado = CType(nodoSeleccionado.Tag, Contacto)
            End If
        End If
        Return contactoSeleccionado
    End Function

    Private Sub ResetearCamposPanelContacto()
        txtNombre.Text = ""
        txtApellido.Text = ""
        txtEmail.Text = ""
        cbCategoria.SelectedItem = Nothing
        dtpFechaNacimiento.Value = Date.Now
        optionSinEspecificar.Checked = True

        'Limpio todos los errores que pueda haber (si hay) en los controles que hay en el panel de contacto
        For Each controlDeContacto As Control In splitContactos.Panel2.Controls
            errorProvider.SetError(controlDeContacto, String.Empty)
        Next
    End Sub

    Private Sub SetearCampos(ByVal contacto As Contacto)
        txtNombre.Text = contacto.Nombre
        txtApellido.Text = contacto.Apellido
        txtEmail.Text = contacto.Email
        cbCategoria.SelectedItem = contacto.Categoria
        dtpFechaNacimiento.Value = contacto.FechaNacimiento
        Select Case contacto.Sexo
            Case Sexo.Femenino
                optionFemenino.Checked = True
            Case Sexo.Masculino
                optionMasculino.Checked = True
            Case Else
                optionSinEspecificar.Checked = True
        End Select
    End Sub

    Private Sub SetearContacto(ByVal contacto As Contacto)
        contacto.Apellido = txtApellido.Text
        contacto.Nombre = txtNombre.Text
        contacto.Email = txtEmail.Text
        contacto.Categoria = CType(cbCategoria.SelectedItem, Categoria)
        contacto.FechaNacimiento = dtpFechaNacimiento.Value
        If (optionFemenino.Checked) Then
            contacto.Sexo = Sexo.Femenino
        ElseIf optionMasculino.Checked Then
            contacto.Sexo = Sexo.Masculino
        Else
            contacto.Sexo = Sexo.SinEspecificar
        End If
    End Sub

    Private Sub btnAceptarContacto_Click(sender As System.Object, e As System.EventArgs) Handles btnAceptarContacto.Click
        Dim contacto As Contacto
        If IsContactoValido() Then
            If modoContacto = Modo.Nuevo Then
                contacto = New Contacto()
            Else
                contacto = getContactoSeleccionado()
            End If
            SetearContacto(contacto)
            If modoContacto = Modo.Edicion Then
                Dim categoriaAnteriorTreeNode As TreeNode = getTreeNodeOfCategoria(contacto.Categoria)
                categoriaAnteriorTreeNode.Nodes.Remove(getTreeNodeOfContacto(contacto))
            End If
            AddContactoToCategoria(contacto.Categoria, contacto)
            ResetearCamposPanelContacto()
        Else
            MessageBox.Show("El contacto tiene campos inválidos", "Error en el formulario", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End If
    End Sub

    Private Sub tvContactos_AfterSelect(sender As System.Object, e As System.Windows.Forms.TreeViewEventArgs) Handles tvContactos.AfterSelect
        If TypeOf e.Node.Tag Is Contacto Then
            modoContacto = Modo.Edicion
            Dim contacto As Contacto
            Contacto = CType(e.Node.Tag, Contacto)
            SetearCampos(Contacto)
        End If
    End Sub

    Private Sub itemSalir_Click(sender As System.Object, e As System.EventArgs) Handles itemSalir.Click
        Me.Close()
    End Sub

    Private Sub btnEliminarContacto_Click(sender As System.Object, e As System.EventArgs) Handles btnEliminarContacto.Click
        Dim contactoSeleccionado As Contacto = getContactoSeleccionado()
        If Not contactoSeleccionado Is Nothing Then
            getTreeNodeOfContacto(contactoSeleccionado).Remove()
            tvContactos.SelectedNode = Nothing
        End If
        modoContacto = Modo.Nuevo
        ResetearCamposPanelContacto()
    End Sub

    Dim id As Integer = 0
    Private Sub btnAgregarTarea_Click(sender As System.Object, e As System.EventArgs) Handles btnAgregarTarea.Click
        If isNombreTareaValido() AndAlso isDescripcionTareaValido() Then
            dgvTareas.Rows.Add(id, txtNombreTarea.Text, txtDescripcionTarea.Text)
            id += 1
        Else
            MessageBox.Show("Los campos son inválidos")
        End If
    End Sub

#Region "Validacion Tarea"
    Private Function isNombreTareaValido() As Boolean
        Return Validador.IsOnlyText(txtNombreTarea.Text)
    End Function

    Private Function isDescripcionTareaValido() As Boolean
        Return Validador.IsOnlyText(txtDescripcionTarea.Text)
    End Function

    Private Sub dgvTareas_CellValidating(sender As System.Object, e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles dgvTareas.CellValidating
        Dim columnName As String = dgvTareas.Columns(e.ColumnIndex).Name
        Select Case columnName
            Case "colNombre"
                'ValidateRow(funcionDeValidacion:=AddressOf Validador.IsOnlyText, texto:=e.FormattedValue.ToString(), rowIndex:=e.RowIndex, message:="El nombre sólo debe contener letras")
                ValidarCeldaConSoloTexto(e.RowIndex, e.ColumnIndex, e.FormattedValue, "El nombre debe contener sólo texto")
            Case "colDescripcion"
                ValidarCeldaConSoloTexto(e.RowIndex, e.ColumnIndex, e.FormattedValue, "La descripción debe contener sólo texto")
        End Select
    End Sub

    Private Sub ValidarCeldaConSoloTexto(fila As Integer, columna As Integer, valor As Object, mensajeDeError As String)
        Dim isOnlyText As Boolean
        isOnlyText = dgvTareas.Rows(fila).Cells(columna).FormattedValueType Is Type.GetType("System.String")
        isOnlyText = isOnlyText AndAlso Validador.IsOnlyText(valor.ToString())

        If Not isOnlyText Then
            dgvTareas.Rows(fila).Cells(columna).ErrorText = mensajeDeError
        Else
            dgvTareas.Rows(fila).Cells(columna).ErrorText = String.Empty
        End If
    End Sub

    Private Sub ValidateRow(funcionDeValidacion As Predicate(Of String), texto As String, rowIndex As Integer, message As String)
        If Not funcionDeValidacion(texto) Then
            dgvTareas.Rows(rowIndex).ErrorText = "El nombre debe ser sólo texto"
        Else
            dgvTareas.Rows(rowIndex).ErrorText = Nothing
        End If
    End Sub
#End Region
    
#Region "Validación contacto"
    Private Sub txtNombreTarea_Validating(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles txtNombreTarea.Validating
        If Not isNombreTareaValido() Then
            errorProvider.SetError(txtNombreTarea, "El nombre debe contener sólo texto")
            e.Cancel = True
        Else
            errorProvider.SetError(txtNombreTarea, String.Empty)
        End If
    End Sub

    Private Sub txtDescripcionTarea_Validating(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles txtDescripcionTarea.Validating
        If Not isDescripcionTareaValido() Then
            errorProvider.SetError(txtDescripcionTarea, "La descripción debe contener sólo texto")
            e.Cancel = True
        Else
            errorProvider.SetError(txtDescripcionTarea, String.Empty)
        End If
    End Sub

    Private Sub txtTexto_Validating(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles txtNombre.Validating, txtApellido.Validating
        Dim control As TextBox = CType(sender, TextBox)
        If Validador.IsOnlyText(control.Text) Then
            errorProvider.SetError(control, String.Empty)
        Else
            errorProvider.SetError(control, "Sólo puede tener letras")
            e.Cancel = True
        End If
    End Sub

    Private Sub dtpFechaNacimiento_Validating(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles dtpFechaNacimiento.Validating
        If isFechaDeNacimientoContactoValida() Then
            errorProvider.SetError(dtpFechaNacimiento, String.Empty)
        Else
            errorProvider.SetError(dtpFechaNacimiento, "La fecha de nacimiento no puede ser mayor a la fecha actual")
            e.Cancel = True
        End If
    End Sub

    Private Sub txtEmail_Validating(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles txtEmail.Validating
        If isEmailDeContactoValido() Then
            errorProvider.SetError(txtEmail, String.Empty)
        Else
            errorProvider.SetError(txtEmail, "Email inválido")
            e.Cancel = True
        End If
    End Sub

    Private Sub cbCategoria_Validating(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles cbCategoria.Validating
        If isCategoriaDeContactoValida() Then
            errorProvider.SetError(cbCategoria, String.Empty)
        Else
            errorProvider.SetError(cbCategoria, "Debe seleccionar alguna categoría")
            e.Cancel = True
        End If
    End Sub

    Private Function isNombreYApellidoContactoValido() As Boolean
        Return Validador.IsOnlyText(txtNombre.Text) AndAlso Validador.IsOnlyText(txtApellido.Text)
    End Function

    Private Function isFechaDeNacimientoContactoValida() As Boolean
        Return dtpFechaNacimiento.Value <= Date.Now
    End Function

    Private Function isCategoriaDeContactoValida() As Boolean
        Return cbCategoria.SelectedIndex <> -1
    End Function

    Private Function isEmailDeContactoValido() As Boolean
        Return Validador.IsValidEmail(txtEmail.Text)
    End Function

    Private Function IsContactoValido() As Boolean
        Return isNombreYApellidoContactoValido() AndAlso isFechaDeNacimientoContactoValida() AndAlso isCategoriaDeContactoValida() AndAlso isEmailDeContactoValido()
    End Function
#End Region
    
End Class

Enum Modo
    Edicion
    Nuevo
End Enum